package cn.xinfei.xdecision.manager.controller.data;


import cn.xinfei.xdecision.common.model.common.ResponseEntityBuilder;
import cn.xinfei.xdecision.common.model.common.ResponseEntityDto;
import cn.xinfei.xdecision.common.model.common.VarPageResult;
import cn.xinfei.xdecision.common.model.datax.datainterface.v2.VarInterfaceInfo;
import cn.xinfei.xdecision.common.model.datax.datamanage.request.*;
import cn.xinfei.xdecision.common.model.datax.datamanage.v2.Variable;
import cn.xinfei.xdecision.common.model.datax.datamanage.v2.vo.VariableDepVO;
import cn.xinfei.xdecision.common.model.datax.datamanage.v2.vo.VariableDetailRespVO;
import cn.xinfei.xdecision.common.model.datax.datamanage.v2.vo.VariableRespVO;
import cn.xinfei.xdecision.common.model.datax.enums.EnumUtil;
import cn.xinfei.xdecision.common.model.datax.enums.VariableEnum;
import cn.xinfei.xdecision.common.model.login.SSOUser;
import cn.xinfei.xdecision.common.model.login.SessionManager;
import cn.xinfei.xdecision.common.service.common.DataConvertUtil;
import cn.xinfei.xdecision.common.service.datax.datainterface.v2.VarInterfaceInfoService;
import cn.xinfei.xdecision.common.service.datax.datamanage.v2.VariableService;
import cn.xinfei.xdecision.common.service.datax.datamanage.v2.VariableSnapshotService;
import cn.xinfei.xdecision.common.utils.constant.OperateNameConst;
import cn.xinfei.xdecision.common.utils.constant.OperateTypeEnum;
import cn.xinfei.xdecision.common.utils.exception.ApiException;
import cn.xinfei.xdecision.common.utils.exception.enums.ErrorCodeEnum;
import cn.xinfei.xdecision.manager.web.aop.ArchivesLog;
import com.alibaba.fastjson.JSONObject;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.google.common.collect.Lists;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Controller;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

@Api(tags = "变量中心")
@Slf4j
@Controller
@RequestMapping("datamanage/derive")
@ResponseBody
public class VariableDeriveController {

    @Autowired
    VariableService variableService;

    @Autowired
    VariableSnapshotService variableSnapshotService;

    @Autowired
    VarInterfaceInfoService varInterfaceInfoService;


    @ApiOperation(value = "查询所有变量")
    @PostMapping("/search")
    public ResponseEntityDto<Object> searchVariable(@RequestBody HashMap<String, Object> paramMap) {

        SSOUser loginAccount = SessionManager.getLoginAccount();
        long organId = loginAccount.getOrganId();
        String searchKey = (String) paramMap.get("searchKey");
        paramMap.put("organId", loginAccount.getOrganId());

        int pageNo = paramMap.get("pageNo") == null ? 1 : Integer.parseInt(paramMap.get("pageNo").toString());
        int pageSize = paramMap.get("pageSize") == null ? 10 : Integer.parseInt(paramMap.get("pageSize").toString());
        PageHelper.startPage(pageNo, pageSize);
        List<Variable> variables;
        if (variableService.checkDefaultSearchVars(paramMap)) {
            variables = variableService.findAllDefaultVars(paramMap);
        } else {
            variables = variableService.searchVariable(paramMap);
        }
        HashMap<String, Object> searchMap = new HashMap<>();
        if (CollectionUtils.isEmpty(variables)) {
            searchMap.put("pager", new ArrayList<>());
            searchMap.put("list", new ArrayList<>());
            return ResponseEntityBuilder.buildNormalResponse(searchMap);
        }
        PageInfo<Variable> pageInfo = new PageInfo<>(variables);
        List<VariableRespVO> variableDTOList = new ArrayList<>();

        Map<Integer, VarInterfaceInfo> varInterfaceInfoMap = Optional.ofNullable(varInterfaceInfoService.SelectAllInterface())
                .orElseGet(Collections::emptyList)
                .stream()
                .collect(Collectors.toMap(VarInterfaceInfo::getId, Function.identity()));
        Map<String, List<VariableDepVO>> varCodesDepVarsMap = variableService.getVarsDep(organId, variables);
        if (CollectionUtils.isNotEmpty(variables)) {
            variables.forEach(variable -> {
                VariableRespVO variableRespVo = new VariableRespVO();
                VariableEnum variableEnum = EnumUtil.fromCodeOrThrow(VariableEnum.class, String.valueOf(variable.getVarType()));
                if (VariableEnum.INTERFACE_VAR.equals(variableEnum)) {
                    VarInterfaceInfo varInterfaceInfo = varInterfaceInfoMap.get(variable.getInterfaceId().intValue());
                    variableRespVo.setInterfaceId(variable.getInterfaceId());
                    Optional.ofNullable(varInterfaceInfo).ifPresent(varInter -> variableRespVo.setSourceType(varInter.getSourceType()));
                }
                Set<String> varDeps = Optional.ofNullable(varCodesDepVarsMap.get(variable.getVarCode()))
                        .orElseGet(Collections::emptyList)
                        .stream().map(VariableDepVO::getVarCode)
                        .filter(Objects::nonNull)
                        .collect(Collectors.toSet());
                variableRespVo.setVarCode(variable.getVarCode());
                variableRespVo.setVarName(variable.getVarName());
                variableRespVo.setVarValueType(String.valueOf(variable.getVarValueType()));
                variableRespVo.setVarType(String.valueOf(variable.getVarType()));
                variableRespVo.setVarDefaultValue(variable.getVarDefaultValue());
                variableRespVo.setDependentVars(varDeps);
                variableRespVo.setIsInput(variable.getIsInput());
                variableRespVo.setIsOutput(variable.getIsOutput());
                variableRespVo.setIsInner(variable.getIsInner());
                variableDTOList.add(variableRespVo);
            });
        }
        searchMap.put("pager", pageInfo);
        searchMap.put("list", variableDTOList);
        searchMap.put("searchKey", searchKey);
        return ResponseEntityBuilder.buildNormalResponse(searchMap);
    }

    @ApiOperation(value = "查询所有非衍生变量")
    @PostMapping("/search/noderive")
    public ResponseEntityDto<Object> searchNoDeriveVariable(@RequestBody HashMap<String, Object> paramMap) {

        SSOUser loginAccount = SessionManager.getLoginAccount();
        long userId = loginAccount.getId();
        long organId = loginAccount.getOrganId();
        String searchKey = (String) paramMap.get("searchKey");
        paramMap.put("organId", organId);
        log.info("searchNoDeriveVariable ,param:{}", JSONObject.toJSONString(paramMap));

        int pageNo = paramMap.get("pageNo") == null ? 1 : Integer.parseInt(paramMap.get("pageNo").toString());
        int pageSize = paramMap.get("pageSize") == null ? 10 : Integer.parseInt(paramMap.get("pageSize").toString());
        PageHelper.startPage(pageNo, pageSize);
        List<Variable> allNotDeriveVariables = variableService.searchNoDerivedVars(paramMap);
        List<VariableRespVO> variableList = Lists.newArrayList();
        Map<String, List<VariableDepVO>> varCodesDepVarsMap = variableService.getVarsDep(organId, allNotDeriveVariables);
        if (CollectionUtils.isNotEmpty(allNotDeriveVariables)) {
            variableList = allNotDeriveVariables.stream().map(var -> {
                Set<String> varDeps = Optional.ofNullable(varCodesDepVarsMap.get(var.getVarCode()))
                        .orElseGet(Collections::emptyList)
                        .stream().map(VariableDepVO::getVarCode)
                        .filter(Objects::nonNull)
                        .collect(Collectors.toSet());
                return DataConvertUtil.convertToVarVo(var, varDeps);
            })
                    .collect(Collectors.toList());
        }
        PageInfo<Variable> pageInfo = new PageInfo<>(allNotDeriveVariables);
        if (CollectionUtils.isEmpty(variableList)) {
            return ResponseEntityBuilder.buildNormalResponse(null);
        }
        HashMap<String, Object> searchMap = new HashMap<>();
        searchMap.put("pager", pageInfo);
        searchMap.put("list", variableList);
        searchMap.put("searchKey", searchKey);
        return ResponseEntityBuilder.buildNormalResponse(searchMap);
    }


    @ApiOperation(value = "添加变量")
    @PostMapping("add")
    @ArchivesLog(type = OperateTypeEnum.CREATE, name = OperateNameConst.VariableOpt.SAVE)
    public ResponseEntityDto<Object> addVariable(@RequestBody VariableSaveAndUpdateParam variableSaveParam) {
        log.info("addVariable ,param:{}", JSONObject.toJSONString(variableSaveParam));
        Long organId = SessionManager.getLoginAccount().getOrganId();
        Long userId = SessionManager.getLoginAccount().getId();
        String userName = SessionManager.getLoginAccount().getName();
        variableSaveParam.setOrganId(organId);
        variableSaveParam.setUserId(userId);
        variableSaveParam.setCreator(userName);
        // check varCode name
        if (!variableService.checkVarCodeNameIsLegal(variableSaveParam.getVarCode())) {
            return ResponseEntityBuilder.buildErrorResponse(ErrorCodeEnum.VAR_CODE_NAME_ERROR);
        }

        // check varCode isDuplicate
        Boolean varCodeIsDuplicate = variableService.checkVarCodeIsDuplicate(variableSaveParam.getVarCode(), organId);
        if (varCodeIsDuplicate) {
            return ResponseEntityBuilder.buildErrorResponse(ErrorCodeEnum.VAR_CODE_EXIST_ERROR);
        }
        // check varName isDuplicate
        Boolean varNameIsDuplicate = variableService.checkVarNameIsDuplicate(variableSaveParam.getVarName(), organId);
        if (varNameIsDuplicate) {
            return ResponseEntityBuilder.buildErrorResponse(ErrorCodeEnum.VAR_NAME_REPEAT);
        }

        return ResponseEntityBuilder.buildNormalResponse(variableService.addVar(variableSaveParam));
    }

    @ApiOperation(value = "更新变量")
    @PostMapping("update")
    @ArchivesLog(type = OperateTypeEnum.UPDATE, name = OperateNameConst.VariableOpt.UPDATE)
    public ResponseEntityDto<Object> updateVariable(@RequestBody VariableSaveAndUpdateParam variableSaveParam) {
        log.info("updateVariable ,param:{}", JSONObject.toJSONString(variableSaveParam));
        Long userId = SessionManager.getLoginAccount().getId();
        Long organId = SessionManager.getLoginAccount().getOrganId();
        String userName = SessionManager.getLoginAccount().getName();
        variableSaveParam.setUserId(userId);
        variableSaveParam.setModifier(userName);
        variableSaveParam.setOrganId(organId);
        // check varName isDuplicate
        Boolean varNameIsDuplicate = variableService.checkVarNameIsDuplicateOnUpdate(
                variableSaveParam.getVarCode(),
                variableSaveParam.getVarName(),
                organId);
        if (varNameIsDuplicate) {
            return ResponseEntityBuilder.buildErrorResponse(ErrorCodeEnum.VAR_NAME_REPEAT);
        }
        return ResponseEntityBuilder.buildNormalResponse(variableService.updateVar(variableSaveParam));
    }

    @ApiOperation(value = "删除变量")
    @PostMapping("delete")
    @ArchivesLog(type = OperateTypeEnum.DELETE, name = OperateNameConst.VariableOpt.DELETE)
    public ResponseEntityDto<Object> deleteVariable(@RequestBody VariableDeleteParam variableSaveParam) {
        log.info("deleteVariable ,param:{}", JSONObject.toJSONString(variableSaveParam));
        Long userId = SessionManager.getLoginAccount().getId();
        Long organId = SessionManager.getLoginAccount().getOrganId();

        variableSaveParam.setUserId(userId);
        variableSaveParam.setOrganId(organId);
        if (CollectionUtils.isNotEmpty(
                variableService.findDepVars(variableSaveParam.getVarCode(), organId)
        )) {
            return ResponseEntityBuilder.buildErrorResponse(ErrorCodeEnum.VAR_CODE_DEPENDENT_ERROR);
        }
        variableService.deleteVar(variableSaveParam);
        return ResponseEntityDto.success("删除变量成功！");
    }

    @ApiOperation(value = "批量删除变量")
    @PostMapping("batchDelete")
    @ArchivesLog(type = OperateTypeEnum.DELETE, name = OperateNameConst.VariableOpt.BATCH_DELETE)
    public ResponseEntityDto<Object> batchDeleteVar(@RequestBody @Validated VariableBatchDeleteParam batchDeleteParam) {
        log.info("batchDeleteVar ,param:{}", JSONObject.toJSONString(batchDeleteParam));
        Long userId = SessionManager.getLoginAccount().getId();
        Long organId = SessionManager.getLoginAccount().getOrganId();
        batchDeleteParam.setUserId(userId);
        batchDeleteParam.setOrganId(organId);
        if (CollectionUtils.isEmpty(batchDeleteParam.getVarCodes())) {
            return ResponseEntityBuilder.buildErrorResponse(ErrorCodeEnum.VAR_CODE_DEPENDENT_ERROR);
        }
        if (CollectionUtils.isNotEmpty(
                Optional.of(batchDeleteParam.getVarCodes())
                        .map(varCodes -> {
                            List<VariableDepVO> depVars = new ArrayList<>();
                            varCodes.forEach(varCode -> {
                                depVars.addAll(variableService.findDepVars(varCode, userId));
                            });
                            return depVars;
                        }).get())
        ) {
            return ResponseEntityBuilder.buildErrorResponse(ErrorCodeEnum.VAR_CODE_DEPENDENT_ERROR);
        }
        if (variableSnapshotService.checkVarCodeUsedInSnapshot(
                new HashSet<>(batchDeleteParam.getVarCodes()),
                organId)) {
            return ResponseEntityBuilder.buildErrorResponse(ErrorCodeEnum.VAR_CODES_USED_IN_SNAPSHOT_ERROR);
        }
        variableService.batchDeleteVar(batchDeleteParam);
        return ResponseEntityDto.success("批量删除变量成功！");
    }

    @ApiOperation(value = "移动变量")
    @PostMapping("batchCopyVar")
    @ArchivesLog(type = OperateTypeEnum.CREATE, name = OperateNameConst.VariableOpt.COPY)
    public ResponseEntityDto<Object> batchCopyVar(@RequestBody @Validated VariableCopyToFolderReqVo copyToFolderReqVo) {
        log.info("copyToFolderReqVo ,param:{}", JSONObject.toJSONString(copyToFolderReqVo));
        Long organId = SessionManager.getLoginAccount().getOrganId();
        Long userId = SessionManager.getLoginAccount().getId();
        String userName = SessionManager.getLoginAccount().getName();
        copyToFolderReqVo.setOrganId(organId);
        copyToFolderReqVo.setModifier(userName);
        copyToFolderReqVo.setUserId(userId);

        if (variableService.checkVarCodeIsDuplicate(copyToFolderReqVo.getVarCopyCode(), organId)) {
            return ResponseEntityBuilder.buildErrorResponse(ErrorCodeEnum.VAR_CODE_EXIST_ERROR);
        }
        if (variableService.checkVarNameIsDuplicate(copyToFolderReqVo.getVarCopyName(), organId)) {
            return ResponseEntityBuilder.buildErrorResponse(ErrorCodeEnum.VAR_NAME_REPEAT);
        }

        try {
            variableService.copyVar(copyToFolderReqVo);
        } catch (ApiException e) {
            return ResponseEntityBuilder.buildErrorResponse(Objects.requireNonNull(ErrorCodeEnum.fromCodeOrThrow(e.getErrCode())));
        }
        return ResponseEntityDto.success("移动变量成功！");
    }


    @ApiOperation(value = "查找变量依赖关系")
    @PostMapping("findDepVars")
    public ResponseEntityDto<Object> findDepVars(@RequestBody @Validated VariableDepReqVO variableDepReqVO) {
        Long organId = SessionManager.getLoginAccount().getOrganId();
        return ResponseEntityDto.success(variableService.findDepVars(variableDepReqVO.getVarCode(), organId));
    }

    @PostMapping("findVarsDep")
    public ResponseEntityDto<Object> findVarsDep(@RequestBody VariableVarsDepReqVO variableVarsDepReqVO) {
        Long organId = SessionManager.getLoginAccount().getOrganId();
        return ResponseEntityDto.success(variableService.findVarsDep(variableVarsDepReqVO.getVarCodes(), organId));
    }


    @ApiOperation(value = "获取变量列表")
    @RequestMapping(value = "/list", method = RequestMethod.POST)
    public ResponseEntityDto<Object> list(@RequestBody HashMap<String, Object> paramMap) {


        SSOUser loginAccount = SessionManager.getLoginAccount();
        paramMap.put("userId", loginAccount.getId());
        paramMap.put("organId", loginAccount.getOrganId());
        String searchKey = (String) paramMap.get("searchKey");

        ResponseEntityDto<VarPageResult<List<VariableRespVO>, Variable>> varPageResult = variableService.findByVarType(paramMap);
        HashMap<String, Object> modelMap = new HashMap<>();
        modelMap.put("pager", varPageResult.getData().getPageInfo());
        modelMap.put("klist", varPageResult.getData().getKlist());
        modelMap.put("searchKey", searchKey);

        return ResponseEntityBuilder.buildNormalResponse(modelMap);
    }

    @ApiOperation(value = "获取接口变量列表")
    @RequestMapping(value = "/interfaceList", method = RequestMethod.POST)
    public ResponseEntityDto<Object> interfaceList(@RequestBody HashMap<String, Object> paramMap) {


        SSOUser loginAccount = SessionManager.getLoginAccount();
        paramMap.put("userId", loginAccount.getId());
        paramMap.put("organId", loginAccount.getOrganId());
        String searchKey = (String) paramMap.get("searchKey");

        ResponseEntityDto<VarPageResult<List<VariableRespVO>, Variable>> varPageResult = variableService.findInterfaceVars(paramMap);
        HashMap<String, Object> modelMap = new HashMap<>();
        modelMap.put("pager", varPageResult.getData().getPageInfo());
        modelMap.put("klist", varPageResult.getData().getKlist());
        modelMap.put("searchKey", searchKey);

        return ResponseEntityBuilder.buildNormalResponse(modelMap);
    }


    @ApiOperation(value = "获取变量列表详情")
    @RequestMapping(value = "/varDetails", method = RequestMethod.POST)
    public ResponseEntityDto<Object> varDetails(@RequestBody VarDetailReqVO varDetailReqVO) {
        SSOUser loginAccount = SessionManager.getLoginAccount();
        varDetailReqVO.setUserId(loginAccount.getId());
        varDetailReqVO.setOrganId(loginAccount.getOrganId());
        List<VariableDetailRespVO> varDetails = variableService.findVarDetails(varDetailReqVO);
        return ResponseEntityBuilder.buildNormalResponse(varDetails);
    }


    @ApiOperation(value = "获取接口变量依赖变量")
    @RequestMapping(value = "/varParams", method = RequestMethod.POST)
    public ResponseEntityDto<Object> varParams(@RequestBody VarParamReqVO varParamReqVO) {
        SSOUser loginAccount = SessionManager.getLoginAccount();
        varParamReqVO.setOrganId(loginAccount.getOrganId());
        List<String> varDetails = variableService.findVarParams(varParamReqVO);
        return ResponseEntityBuilder.buildNormalResponse(varDetails);
    }


    @ApiOperation(value = "判断用户是否是超级管理员")
    @RequestMapping(value = "/isSuperAdminUser", method = RequestMethod.POST)
    public ResponseEntityDto<Object> isSuperAdminUser(@RequestBody @Validated VarSuperAdminUserReqVO userReqVO) {
        boolean isSupderAdminUser = variableService.checkSuperAdminUser(userReqVO);
        return ResponseEntityBuilder.buildNormalResponse(isSupderAdminUser);
    }

    @ApiOperation(value = "获取变量中心枚举值")
    @RequestMapping(value = "/enum", method = RequestMethod.GET)
    public ResponseEntityDto<Object> enumList(@Param("type") String type) {
        return ResponseEntityBuilder.buildNormalResponse(variableService.getEnumList(type));
    }


    @ApiOperation(value = "恢复变量快照版本")
    @PostMapping("resumeVarSnapShot")
    @ArchivesLog(type = OperateTypeEnum.UPDATE, name = OperateNameConst.VariableOpt.SNAPSHOT_RECOVER)
    public ResponseEntityDto<Object> resumeVarSnapShot(@RequestBody @Validated VarSnapshotReqVO varSnapshotReqVO) {
        Long organId = SessionManager.getLoginAccount().getOrganId();
        try {
            variableService.resumeVarSnapShot(varSnapshotReqVO.getVarCode(), varSnapshotReqVO.getVersionId(), organId);
        } catch (ApiException e) {
            if (((ApiException) e.getCause()).getErrCode().equals(ErrorCodeEnum.VAR_NAME_REPEAT.getCode())) {
                return ResponseEntityBuilder.buildErrorResponse(ErrorCodeEnum.VAR_NAME_REPEAT);
            } else {
                return ResponseEntityBuilder.buildErrorResponse(Objects.requireNonNull(ErrorCodeEnum.fromCodeOrThrow(e.getErrCode())));
            }
        }
        return ResponseEntityDto.success("恢复变量快照版本成功!");
    }

    @ApiOperation(value = "变量快照详情")
    @PostMapping("getSnapShotInfo")
    public ResponseEntityDto<Object> getSnapShotInfo(@RequestBody @Validated VarSnapshotReqVO varSnapshotReqVO) {
        Long organId = SessionManager.getLoginAccount().getOrganId();
        return ResponseEntityDto.success(variableSnapshotService.getSnapshotInfo(varSnapshotReqVO.getVarCode(), varSnapshotReqVO.getVersionId(), organId));
    }

    @ApiOperation(value = "变量快照list")
    @PostMapping("getSnapShotInfoList")
    public ResponseEntityDto<Object> getSnapShotInfoList(@RequestBody @Validated VarSnapshotListReqVO varSnapshotReqVO) {
        Long organId = SessionManager.getLoginAccount().getOrganId();
        return ResponseEntityDto.success(variableSnapshotService.getSnapshotDetails(varSnapshotReqVO.getVarCode(), organId));
    }

    @ApiOperation(value = "查询业务引擎标签")
    @PostMapping("findBussinessVarsByOrganId")
    public ResponseEntityDto<Object> findBussinessVarsByOrganId(@RequestBody @Validated VarBussinessLabelReqVO varBussinessLabelReqVO) {
        return ResponseEntityDto.success(variableService.findBussinessVarsByOrganId(varBussinessLabelReqVO.getOrganId()));
    }


}
